using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JetBrains.Annotations;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.UI;

namespace Dolls
{
	public class CharsForeach : MonoBehaviour
	{
		public Text   textComponent;
		public string origin;
		public float  secondsPerChar;

		[CanBeNull]
		private string Current { get; set; }

		private Coroutine _coroutine = null;

		/// <summary>
		/// 显示完成的事件
		/// </summary>
		public event Action<CharsForeach> FinishedEventHandle;

		/// <summary>
		/// unity富文本的可用标签
		/// </summary>
		private static readonly ISet<string> AvailableTagName = new HashSet<string>
		{
			"b",
			"i",
			"size",
			"color",
			"material",
			"quad"
		};

		/// <summary>
		/// 开始显示
		/// </summary>
		/// <param name="s">显示的文本内容</param>
		public void DisplayIndividually(string s)
		{
			Init(s);
			_coroutine = StartCoroutine(DisplayIndividuallyImpl());
		}

		/// <summary>
		/// 立即显示
		/// </summary>
		/// <param name="s"></param>
		public void DisplayImmediately([CanBeNull] string s)
		{
			Init(s);
			textComponent.text = origin;
			FinishedEventHandle?.Invoke(this);
		}

		/// <summary>
		/// 初始化待显示的内容
		/// </summary>
		private void Init(string s)
		{
			Assert.IsFalse(string.IsNullOrWhiteSpace(s));
			origin             = s;
			textComponent.text = "";
			Current            = "";

			if (textComponent == null)
				textComponent = GetComponent<Text>();
			if (_coroutine != null)
				StopCoroutine(_coroutine);
		}

		private IEnumerator DisplayIndividuallyImpl()
		{
			//若文本框支持富文本则尝试解析富文本标记
			if (textComponent.supportRichText)
			{
				var tagList = new List<string>();
				for (var i = 0; i < origin.Length; i++)
				{
					var c = origin[i];
					//处理富文本标记
					if (c == '<')
					{
						var builder = new StringBuilder();
						//标记是否完整
						var find = false;
						//是否是右标记
						var isRightTag = (i + 1) < origin.Length && origin[i + 1] == '/';

						//搜索标记结束
						var j = i;
						for (; j < origin.Length; j++)
						{
							var c1 = origin[j];
							builder.Append(c1);
							// ReSharper disable once InvertIf
							if (c1 == '>')
							{
								find = true;
								break;
							}
						}

						//找到完整的富文本标记
						if (find)
						{
							var currentTag = builder.ToString();
							var tagName    = GetTagName(currentTag, isRightTag);
							if (AvailableTagName.Contains(tagName)) //是Unity的富文本标记
							{
								if (isRightTag) //是右标记且前一个标记存在，则比对前一个标记
								{
									if (tagList.Count > 0 && GetTagName(tagList[^1], false) == tagName)
									{
										//与前一个标记匹配，塞入右标记，左标记弹出，扫描右标记后的字符
										Current += currentTag;
										tagList.RemoveAt(tagList.Count - 1);
										i = j;
										continue;
									}
									//前标记不存在或不匹配，标记不完整，直接输出
								} else //左标记入栈，并且输出，扫描标记后的下一个字符
								{
									tagList.Add(currentTag);
									Current += currentTag;
									i       =  j;
									continue;
								}
							}
						}
					}

					Current += origin[i];
					//生成左标记对应的右标记塞回去
					var rightTagsBuilder = new StringBuilder(Current);
					for (var j = tagList.Count - 1; j >= 0; j--)
						rightTagsBuilder.Append("</")
										.Append(GetTagName(tagList[j], false))
										.Append(">");

					textComponent.text = rightTagsBuilder.ToString();
					yield return new WaitForSeconds(secondsPerChar);
				}
			} else
			{
				foreach (var c in origin)
				{
					textComponent.text += c;
					yield return new WaitForSeconds(secondsPerChar);
				}
			}

			FinishedEventHandle?.Invoke(this);
		}

		/// <summary>
		/// 从完整的标记中获取标记名
		/// </summary>
		/// <param name="fullTag">包含尖括号的完整标记</param>
		/// <param name="isRight">是否右标记</param>
		/// <returns></returns>
		private static string GetTagName(string fullTag, bool isRight)
		{
			return isRight ? fullTag[2..^1] : fullTag[1..(fullTag.IndexOfAny(new[] { ' ', '=', '>' }))];
		}
	}
}